home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HAM Radio 3.2
/
Ham Radio Version 3.2 (Chestnut CD-ROMs)(1993).ISO
/
packet
/
n17jsrc
/
dialer.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-06-25
|
9KB
|
382 lines
/* Automatic SLIP/PPP line dialer.
*
* Copyright 1991 Phil Karn, KA9Q
*
* Mar '91 Bill Simpson & Glenn McGregor
* completely re-written;
* human readable control file;
* includes wait for string, and speed sense;
* dials immediately when invoked.
* May '91 Bill Simpson
* re-ordered command line;
* allow dial only;
* allow inactivity timeout without ping.
*/
/* mods by PA0GRI */
#include <stdio.h>
#include <ctype.h>
#include "global.h"
#include "config.h"
#include "mbuf.h"
#include "timer.h"
#include "proc.h"
#include "iface.h"
#include "netuser.h"
#include "8250.h"
#include "asy.h"
#include "tty.h"
#include "session.h"
#include "socket.h"
#include "cmdparse.h"
#include "devparam.h"
#include "icmp.h"
#include "files.h"
#include "main.h"
#include "trace.h"
#define MIN_INTERVAL 5L
static int redial __ARGS((struct iface *ifp,char *file));
static int dodial_control __ARGS((int argc,char *argv[],void *p));
static int dodial_send __ARGS((int argc,char *argv[],void *p));
static int dodial_speed __ARGS((int argc,char *argv[],void *p));
static int dodial_wait __ARGS((int argc,char *argv[],void *p));
static struct cmds dial_cmds[] = {
"control", dodial_control, 0, 2, "control up | down",
"send", dodial_send, 0, 2,
"send \"string\" [<milliseconds>]",
"speed", dodial_speed, 0, 2, "speed <bps>",
"wait", dodial_wait, 0, 2,
"wait <milliseconds> [ \"string\" [speed] ]",
NULLCHAR, NULLFP, 0, 0, "Unknown command",
};
/* dial <iface> <filename> [ <seconds> [ <pings> [<hostid>] ] ]
* <iface> must be asy type
* <filename> contains commands which are executed.
* missing: kill outstanding dialer.
* <seconds> interval to check for activity on <iface>.
* <pings> number of missed pings before redial.
* <hostid> interface to ping.
*/
int
dodialer(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct iface *ifp;
int32 interval = 0L; /* in seconds */
int32 last_wait = 0L;
int32 target = 0L;
int pings = 0;
int countdown;
char *filename;
char *ifn;
int result;
int s;
if((ifp = if_lookup(argv[1])) == NULLIF){
tprintf("Interface %s unknown\n",argv[1]);
return 1;
}
if( ifp->dev >= ASY_MAX || Asy[ifp->dev].iface != ifp ){
tprintf("Interface %s not asy port\n",argv[1]);
return 1;
}
if(ifp->supv != NULLPROC){
while ( ifp->supv != NULLPROC ) {
alert(ifp->supv, EABORT);
pwait(NULL);
}
tprintf("dialer terminated on %s\n",argv[1]);
}
if ( argc < 3 ) {
/* just terminating */
return 0;
}
chname( Curproc, ifn = if_name( ifp, " dialer" ) );
free( ifn );
filename = rootdircat(argv[2]);
/* handle minimal command (just thru filename) */
if ( argc < 4 ) {
/* just dialing */
result = redial(ifp, filename);
if ( filename != argv[2] )
free(filename);
return result;
/* get polling interval (arg 3) */
} else if ( (interval = atol(argv[3])) <= MIN_INTERVAL ) {
tprintf("interval must be > %d seconds\n", MIN_INTERVAL);
return 1;
}
/* get the number of pings before redialing (arg 4) */
if ( argc < 5 ) {
} else if ( (pings = atoi(argv[4])) <= 0 ){
tprintf("pings must be > 0\n");
return 1;
}
/* retrieve the host name (arg 5) */
if ( argc < 6 ) {
} else if ( (target = resolve(argv[5])) == 0L ) {
tprintf(Badhost,argv[5]);
return 1;
}
countdown = pings;
ifp->supv = Curproc;
while ( !main_exit ) {
int32 wait_for = interval;
if ( Asy[ ifp->dev ].rlsd_line_control == RLSD_DOWN ) {
/* definitely down */
if ( redial(ifp,filename) < 0 )
break;
} else if ( ifp->lastrecv >= last_wait ) {
/* got something recently */
wait_for -= secclock() - ifp->lastrecv;
countdown = pings;
} else if ( countdown < 1 ) {
/* we're down, or host we ping is down */
if ( redial(ifp,filename) < 0 )
break;
} else if ( target != 0L
&& (s = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP)) != -1 ) {
pingem(s,target,0,(int16)s,0);
close_s(s);
countdown--;
} else if ( ifp->echo != NULLFP ) {
(*ifp->echo)(ifp,NULLBUF);
countdown--;
}
last_wait = secclock();
if ( wait_for != 0L ) {
alarm( wait_for * 1000L );
if ( pwait( &(ifp->supv) ) == EABORT )
break;
alarm(0L); /* clear alarm */
}
}
if ( filename != argv[2] )
free(filename);
ifp->supv = NULLPROC; /* We're being terminated */
return 0;
}
/* execute dialer commands
* returns: -1 fatal error, 0 OK, 1 try again
*/
static int
redial( ifp, file )
struct iface *ifp;
char *file;
{
char *inbuf, *intmp;
FILE *fp;
int (*rawsave) __ARGS((struct iface *,struct mbuf *));
struct session *sp;
int result = 0;
int save_input = Curproc->input;
int save_output = Curproc->output;
if((fp = fopen(file,READ_TEXT)) == NULLFILE){
tprintf("redial: can't read %s\n",file);
return -1; /* Causes dialer proc to terminate */
}
/* Save output handler and temporarily redirect output to null */
if(ifp->raw == bitbucket){
tprintf("redial: tip or dialer already active on %s\n",ifp->name);
return -1;
}
/* allocate a session descriptor */
if ( (sp = newsession( ifp->name, DIAL, 0 )) == NULLSESSION ) {
tprintf( "Too many sessions\n" );
return 1;
}
tprintf( "Dialing on %s\n\n", ifp->name );
/* Save output handler and temporarily redirect output to null */
rawsave = ifp->raw;
ifp->raw = bitbucket;
/* Suspend the packet input driver. Note that the transmit driver
* is left running since we use it to send buffers to the line.
*/
suspend(ifp->rxproc);
inbuf = mallocw(BUFSIZ);
intmp = mallocw(BUFSIZ);
while ( fgets( inbuf, BUFSIZ, fp ) != NULLCHAR ) {
strcpy(intmp,inbuf);
if( (result = cmdparse(dial_cmds,inbuf,ifp)) != 0 ){
tprintf("input line: %s",intmp);
break;
}
}
free(inbuf);
free(intmp);
fclose(fp);
if ( result == 0 ) {
ifp->lastsent = ifp->lastrecv = secclock();
}
ifp->raw = rawsave;
resume(ifp->rxproc);
tprintf( "\nDial %s complete\n", ifp->name );
/* Wait for awhile, so the user can read the screen,
* AND to give it time to send some packets on the new connection!
*/
pause( 10000L );
freesession( sp );
Curproc->input = save_input;
Curproc->output = save_output;
return result;
}
static int
dodial_control(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct iface *ifp = p;
int param;
if ( ifp->ioctl == NULL )
return -1;
if ( (param = devparam( argv[1] )) == -1 )
return -1;
(*ifp->ioctl)( ifp, param, TRUE, atol( argv[2] ) );
return 0;
}
static int
dodial_send(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct iface *ifp = p;
struct mbuf *bp;
if(argc > 2){
/* Send characters with inter-character delay
* (for dealing with prehistoric Micom switches that
* can't take back-to-back characters...yes, they
* still exist.)
*/
char *cp;
int32 cdelay = atol(argv[2]);
for(cp = argv[1];*cp != '\0';cp++){
bp = qdata(cp,1);
asy_send(ifp->dev,bp);
pause(cdelay);
}
} else {
bp = qdata( argv[1], strlen(argv[1]) );
if (ifp->trace & IF_TRACE_RAW)
raw_dump( ifp, IF_TRACE_OUT, bp );
asy_send( ifp->dev, bp );
}
return 0;
}
static int
dodial_speed(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct iface *ifp = p;
if ( argc < 2 ) {
tprintf( "current speed = %u bps\n", Asy[ifp->dev].speed );
return 0;
}
return asy_speed( ifp->dev, (int16)atol( argv[1] ) );
}
static int
dodial_wait(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct iface *ifp = p;
register int c = -1;
alarm( atol( argv[1] ) );
if ( argc == 2 ) {
while ( (c = get_asy(ifp->dev)) != -1 ) {
tputc( c &= 0x7F );
tflush();
}
alarm( 0L );
return 0;
} else {
register char *cp = argv[2];
while ( *cp != '\0' && (c = get_asy(ifp->dev)) != -1 ) {
tputc( c &= 0x7F );
tflush();
if (*cp++ != c) {
cp = argv[2];
}
}
if ( argc > 3 ) {
if ( stricmp( argv[3], "speed" ) == 0 ){
int16 speed = 0;
while ( (c = get_asy(ifp->dev)) != -1 ) {
tputc( c &= 0x7F );
tflush();
if ( isdigit(c) ) {
speed *= 10;
speed += c - '0';
} else {
alarm( 0L );
return asy_speed( ifp->dev, speed );
}
}
} else {
return -1;
}
}
}
alarm( 0L );
return ( c == -1 );
}